//-------------------------------------------------------------------------------------------//
// Copyright(c) Wang Yong
// Author     : Wang Yong
// Date       : 2021-05-30
// Description: Refine the tetrahedron mesh by split the marked element. It is designed for
// FEM adaptive mesh function.
//-------------------------------------------------------------------------------------------//
#ifndef TETR_MESH_REFINE_H
#define TETR_MESH_REFINE_H
#include "MeshRefine.h"

using namespace Mesher;

constexpr Real MINGAP = 1.0e-10;

enum SPLIT_TYPE {
    NOT_SPLIT  = 0,
    Edge1Type1 = 1,
    Edge2Type2 = 2,
    Edge2Type3 = 3,
    Edge3Type4 = 4,
    Edge3Type5 = 5,
    Edge3Type6 = 6,
    Edge4Type7 = 7,
    Edge4Type8 = 8,
    Edge5Type9 = 9,
    AllSixEdge = 10
};

class RefineTetr
{
public:
    RefineTetr() = default;
    ~RefineTetr() = default;
    // find all common edge
    void fn_FindTetrEdges(std::vector<Node> &vR, std::vector<Tetr> &vElem);
    // mark the edges need to be splitted
    void fn_MarkSplitEdge(std::vector<Tetr> &vElem, std::vector<bool> &vRefine);
    // adapt the edge to improve the mesh quality
    void fn_AdaptTetrEdge(std::vector<Tetr> &vElem);
    // check and update the split edge number
    void fn_CheckTetrType(std::vector<Tetr> &vElem);
    // insert new point on each edge
    void fn_AddEdgesPoint(std::vector<Tetr> &vElem, std::vector<Node> &vR);
    // split each element
    void fn_SplitEachTetr(std::vector<Node> &vR, std::vector<Tetr> &vElem);
    // optimize the mesh
    void fn_OptimizTetMsh(std::vector<Node> &vR, std::vector<Tetr> &vElem);

private:
    std::vector<std::vector<int>> m_vTetrEdge;
    std::vector<Real> m_vEdgeLen;
    std::vector<bool> m_vEdgeFlag;
    std::vector<int>  m_vEdgeNode;
    std::vector<int>  m_vTetrType;

    // split only one tetrahedra edge
    void fn_CutEdge1Type1(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split two tetrahedra edges
    void fn_CutEdge2Type2(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split two tetrahedra edges
    void fn_CutEdge2Type3(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split three tetrahedra edges
    void fn_CutEdge3Type4(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split three tetrahedra edges
    void fn_CutEdge3Type5(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split three tetrahedra edges
    void fn_CutEdge3Type6(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split four tetrahedra edge
    void fn_CutEdge4Type7(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split four tetrahedra edge
    void fn_CutEdge4Type8(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split five tetrahedra edges
    void fn_CutEdge5Type9(Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
    // split all six tetrahedra edges
    void fn_CutAllSixEdge(std::vector<Node> &vR, Tetr &oldTetr, std::vector<int> &vEdgeIndx, std::vector<Tetr> &vNewTetr);
};

#endif